#include "pch.h"
#include "GameObject.h"
#include "GameEngine.h"
#include "../Rendering/ConstantBuffers.h"

using namespace DirectX;

#define TARGET_FPS	60.0f

GameObject::GameObject() :
	m_material(nullptr)
{
	m_active		  = true;
	m_position        = XMFLOAT3(0.0f, 0.0f, 0.0f);
	m_oldPosition     = XMFLOAT3(0.0f, 0.0f, 0.0f);
	m_velocity        = XMFLOAT3(0.0f, 0.0f, 0.0f);
	m_defaultXAxis    = XMFLOAT3(1.0f, 0.0f, 0.0f);
	m_defaultYAxis    = XMFLOAT3(0.0f, 1.0f, 0.0f);
	m_defaultZAxis    = XMFLOAT3(0.0f, 0.0f, 1.0f);
	m_scale           = XMFLOAT3(1.0f, 1.0f, 1.0f);
	m_pulseState      = PulseState::None;
	XMStoreFloat4x4(&m_modelMatrix, XMMatrixIdentity());
}

void GameObject::PulseColor(DirectX::XMFLOAT4 color, float fadeUp, float duration, float fadeDown, float colorMaxPercent, float diffuseMinPercent)
{
	m_pulseColor = color;
	m_fadeUp = fadeUp;
	m_duration = duration;
	m_fadeDown = fadeDown;
	m_colorMaxPercent = colorMaxPercent;
	m_diffuseMinPercent = diffuseMinPercent;
	// If we're not at none, we should already have the originals stored and could only expect incorrect values from this.
	if (m_pulseState == PulseState::None)
	{
		m_colorAndDiffuseOriginalPercents = m_material->MeshPercentDiffusePercent();
	}
	m_pulseState = PulseState::Start;
}

void GameObject::EndPulse()
{
	if(m_pulseState != PulseState::None)
	{
		m_pulseState = PulseState::None;
		// Set the mesh back to its original mesh color and percentages
		m_material->MeshColor(m_material->OriginalColor());
		m_material->DiffusePercent(m_colorAndDiffuseOriginalPercents.y);
		m_material->MeshPercent(m_colorAndDiffuseOriginalPercents.x);
	}
}

void GameObject::Update(GameEngine^ engine)
{
	float time = engine->GetGameTimer()->PlayingTime();

	switch(m_pulseState)
	{
		case PulseState::None:
			break;

		case PulseState::Start:
			m_material->MeshColor(m_pulseColor);

			m_pulseTimer = time;
			m_pulseState = PulseState::FadeUp;
			break;

		case PulseState::FadeUp:
			if(time - m_pulseTimer > m_fadeUp)
			{
				m_pulseTimer = time;
				m_pulseState = PulseState::Duration;
				m_material->MeshPercent(m_colorMaxPercent);
				m_material->DiffusePercent(m_diffuseMinPercent);
			}
			else
			{
				auto fraction = (time - m_pulseTimer) / m_fadeUp;
				// Lerp from the original value up to the max value.
				m_material->MeshPercent(m_colorAndDiffuseOriginalPercents.x + fabsf(m_colorMaxPercent - m_colorAndDiffuseOriginalPercents.x) * fraction);
				// Lerp from the original value down to the min value.
				m_material->DiffusePercent(m_colorAndDiffuseOriginalPercents.y - fabsf(m_diffuseMinPercent - m_colorAndDiffuseOriginalPercents.y) * fraction);
			}
			break;

		case PulseState::Duration:
			if(time - m_pulseTimer > m_duration)
			{
				m_pulseTimer = time;
				m_pulseState = PulseState::FadeDown;
			}

			m_material->MeshPercent(m_colorMaxPercent);
			m_material->DiffusePercent(m_diffuseMinPercent);
			break;

		case PulseState::FadeDown:
			if(time - m_pulseTimer > m_fadeDown)
			{
				m_material->MeshColor(m_material->OriginalColor());

				m_pulseTimer = time;
				m_pulseState = PulseState::None;

				m_material->DiffusePercent(m_colorAndDiffuseOriginalPercents.y);
				m_material->MeshPercent(m_colorAndDiffuseOriginalPercents.x);
			}
			else
			{
				auto fraction = (time - m_pulseTimer) / m_fadeDown;
				// Lerp from the max value up to original max value.
				m_material->MeshPercent(m_colorMaxPercent - fabsf(m_colorMaxPercent - m_colorAndDiffuseOriginalPercents.x) * fraction);
				// Lerp from the min value down to the original value.
				m_material->DiffusePercent(m_diffuseMinPercent + fabsf(m_diffuseMinPercent - m_colorAndDiffuseOriginalPercents.y) * fraction);
			}
			break;
	}

	Position(VectorPosition() + (VectorVelocity() * engine->GetGameTimer()->DeltaTime()));

	XMStoreFloat4x4(
		&m_modelMatrix,
		XMMatrixScaling(m_scale.x, m_scale.y, m_scale.z) *
		XMMatrixRotationRollPitchYaw(m_rotation.x, m_rotation.y, m_rotation.z) *
		XMMatrixTranslation(m_position.x, m_position.y, m_position.z)
	);
}

void GameObject::Render(
	_In_ ID3D11DeviceContext *context,
	_In_ ID3D11Buffer *primitiveConstantBuffer,
	_In_ bool isFirstPass
	)
{
	if ( m_mesh == nullptr )
		return;

	XMFLOAT4X4 world;
	XMStoreFloat4x4(
		&world,
		XMMatrixTranspose(ModelMatrix())
		);

	m_material->RenderSetup(context, world, primitiveConstantBuffer, isFirstPass);
	m_mesh->Render(context, isFirstPass);
}
